package com.ruoyi.asset.cleaning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.asset.cleaning.constant.SweepCleaningDirtConstant;
import com.ruoyi.asset.cleaning.domain.SweepCleaning;
import com.ruoyi.asset.cleaning.domain.bo.*;
import com.ruoyi.asset.cleaning.domain.vo.SweepCleaningVo;
import com.ruoyi.asset.cleaning.mapper.SweepCleaningMapper;
import com.ruoyi.asset.cleaning.service.ISweepCleaningService;
import com.ruoyi.asset.common.scopecode.constant.ServiceCode;
import com.ruoyi.asset.common.scopecode.service.IScopeCodeService;
import com.ruoyi.asset.homepage.constant.CommunityConstant;
import com.ruoyi.asset.homepage.constant.ServiceTypeConstant;
import com.ruoyi.asset.tool.domain.bo.ToolStatisticsBo;
import com.ruoyi.asset.tool.service.IToolService;
import com.ruoyi.asset.workman.service.IWorkmanService;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.tools.excel.MyExcelUtil;
import com.ruoyi.common.tools.excel.base.MyExcelResult;
import com.ruoyi.common.tools.excel.listener.asset.CleaningExcelListener;
import com.ruoyi.common.tools.utils.SerialGenerator;
import com.ruoyi.common.utils.BeanCopyUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.erecord.region.service.IRegionService;
import com.ruoyi.standingbook.cleaning.service.ICleaningService;
import com.ruoyi.system.service.ISysDictDataService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;


import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author 12276
 */
@RequiredArgsConstructor
@Service
public class SweepCleaningServiceImpl implements ISweepCleaningService {

    private final SweepCleaningMapper sweepCleaningMapper;
    private final ICleaningService cleaningService;
    private IToolService toolService = SpringUtils.getBean(IToolService.class);
    private IRegionService regionService = SpringUtils.getBean(IRegionService.class);
    private IWorkmanService workmanService = SpringUtils.getBean(IWorkmanService.class);
    private ISysDictDataService sysDictDataService = SpringUtils.getBean(ISysDictDataService.class);

    private final IScopeCodeService scopeCodeService;

    private Boolean batchInsertOrUpdate(List<SweepCleaning> voList) {
        return this.sweepCleaningMapper.insertOrUpdateBatch(voList);
    }

    @Override
    public List<String> importExcel(String excelUrl) {
        List<String> errorMsgList = new ArrayList<>();

        // 生成批次号
        final String batchNo = SerialGenerator.generator.nextId();

        // excel 处理
        MyExcelResult<SweepCleaningVo> excelResult = MyExcelUtil.getImportExcelData(batchNo, excelUrl,
            new CleaningExcelListener(batchNo), SweepCleaningVo.class, true);

        if (null == excelResult) {
            errorMsgList.add("未获取到要处理的数据");

            return null;
        }

        /**
         *  有解析失败就直接返回错误信息
         */
        if(!excelResult.getErrorList().isEmpty()) {
            return excelResult.getErrorList();
        }

        if (!excelResult.getList().isEmpty()) {
            List<SweepCleaning> list = new ArrayList<>();
            AtomicInteger row = new AtomicInteger(0);
            excelResult.getList().forEach(e -> {
                int currentRow = row.incrementAndGet();
                if (e.getDataCheckResult().isSucess()) {
                    SweepCleaning sweepCleaning = new SweepCleaning();

                    BeanCopyUtils.copy(e, sweepCleaning);

                    SweepCleaning oldLampMaintenance = getVoByCondition(sweepCleaning.getRoadName(),
                        sweepCleaning.getRoadType());

                    if (oldLampMaintenance != null) {
                        sweepCleaning.setId(oldLampMaintenance.getId());
                    } else {
                        String scopeCode = null;

                        try {
                            scopeCode = scopeCodeService.getNextScopeCode(ServiceCode.CLEANING,
                                sweepCleaning.getRoadType(), "");
                        } catch (Exception ex) {
                            errorMsgList.add("获取管理范围编码失败，失败原因：" + ex.getMessage());
                        }

                        sweepCleaning.setScopeCode(scopeCode);
                    }

                    /**
                     *  如果各行数据校验通过，再遍历检查是否数据重复
                     */
                    if(excelResult.getValidateList().isEmpty()){
                        AtomicInteger count = new AtomicInteger(0);
                        list.stream().anyMatch(f->{
                            int currentCount = count.incrementAndGet();
                            if (f.getRoadName().equals(sweepCleaning.getRoadName()) && f.getRoadType().equals(sweepCleaning.getRoadType())) {
                                errorMsgList.add(String.format("第%d行数据检查失败，失败原因：与第%s行数据重复",currentRow, currentCount));
                                return true;
                            }
                            return false;
                        });
                    }

                    list.add(sweepCleaning);
                } else {
                    errorMsgList.add(String.format("第 %d 行数据检查失败，失败原因：%s", currentRow, e.getDataCheckResult().getMsg()));
                }
            });

            if (errorMsgList.isEmpty()) {
                batchInsertOrUpdate(list);
            }
        }

        return errorMsgList;
    }

    private SweepCleaning getVoByCondition(String roadName, String roadType) {
        LambdaQueryWrapper<SweepCleaning> lqw = Wrappers.lambdaQuery();

        lqw.eq(SweepCleaning::getRoadName, roadName);
        lqw.eq(SweepCleaning::getRoadType, roadType);
        lqw.eq(SweepCleaning::getDelFlag,0);
        List<SweepCleaning> list = sweepCleaningMapper.selectList(lqw);

        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public int deleteCleaning(Set<Long> idsSet) {
        if (CollectionUtils.isEmpty(idsSet)) {
            return -1;
        }
        return sweepCleaningMapper.logicDeleteCleaning(idsSet);
    }

    @Override
    public TableDataInfo<SweepCleaningVo> queryCleaning(SweepCleaningBo searchBo, PageQuery pageQuery) {
        Page<SweepCleaningVo> result = sweepCleaningMapper.selectCleaning(pageQuery.build(), searchBo);
        ArrayList<SweepCleaningVo> list = new ArrayList<>();
        result.getRecords().forEach(e -> {
            SweepCleaningVo sweepCleaningVo = new SweepCleaningVo();
            BeanCopyUtils.copy(e, sweepCleaningVo);
            String roadType = sysDictDataService.selectDictLabel(SweepCleaningDirtConstant.CLEANING_TYPE, sweepCleaningVo.getRoadType());
            if (StringUtils.isNotBlank(roadType)){
                sweepCleaningVo.setRoadType(roadType);
            }
            list.add(sweepCleaningVo);

        });
        result.setRecords(list);
        return TableDataInfo.build(result);
    }

    @Override
    public List<SweepCleaningVo> exportCleaning(SweepCleaningBo searchBo) {
        ArrayList<SweepCleaningVo> list = new ArrayList<>();
        sweepCleaningMapper.exportCleaning(searchBo).forEach(e->{
            SweepCleaningVo sweepCleaningVo = new SweepCleaningVo();
            BeanCopyUtils.copy(e, sweepCleaningVo);
            String roadType = sysDictDataService.selectDictLabel(SweepCleaningDirtConstant.CLEANING_TYPE, sweepCleaningVo.getRoadType());
            if (StringUtils.isNotBlank(roadType)){
                sweepCleaningVo.setRoadType(roadType);
            }
            list.add(sweepCleaningVo);
        });
        return list;
    }

    @Override
    public SweepCleaningStatisticsBo getCleaningCount() {
        SweepCleaningStatisticsBo statisticsBo = new SweepCleaningStatisticsBo();
        Double areaSum = sweepCleaningMapper.selectAreaCount();
        if (null != areaSum) {
            statisticsBo.setAreaSum(areaSum);
        } else {
            statisticsBo.setAreaSum(0.00);
        }
        int workCount = workmanService.getByServiceType(ServiceTypeConstant.CLEANING);
        statisticsBo.setWorkerCount(workCount);
        ToolStatisticsBo toolStatisticsBo = toolService.getCountByServiceType(ServiceTypeConstant.CLEANING);
        if (null != toolStatisticsBo) {
            statisticsBo.setEquipmentCount(toolStatisticsBo.getToolCount());
            statisticsBo.setVehicleCount(toolStatisticsBo.getVehicleCount());
        } else {
            statisticsBo.setEquipmentCount(0);
            statisticsBo.setVehicleCount(0);
        }
        return statisticsBo;
    }

    @Override
    public Map getCleaningCommunity() {
        HashMap<String, CleaningCommunityBo> map = new HashMap<>();
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(CommunityConstant.COMMUNITY_TYPE);
        List<SysDictData> data = sysDictDataService.selectDictDataList(sysDictData);
        for (SysDictData community : data) {
            String communityNo = regionService.getRegionIdByName(community.getDictLabel());
            List<CleaningRoadTypeBo> cleaningRoadTypeBos = sweepCleaningMapper.selectCommunityAreaCount(communityNo);
            cleaningRoadTypeBos.forEach(e->{
                String roadName = sysDictDataService.selectDictLabel(SweepCleaningDirtConstant.CLEANING_TYPE, e.getRoadType());
                if (StringUtils.isNotBlank(roadName)) {
                    e.setRoadType(roadName);
                }
            });
            CleaningCommunityBo cleaningCommunityBo = new CleaningCommunityBo();
            cleaningCommunityBo.setCleaningRoadTypeBoList(cleaningRoadTypeBos);
            ToolStatisticsBo toolCount = toolService.getCountByServiceTypeAndCommunity(ServiceTypeConstant.CLEANING, communityNo);
            cleaningCommunityBo.setToolCount(toolCount.getToolCount());
            cleaningCommunityBo.setVehicleCount(toolCount.getVehicleCount());
            int workmanCount = workmanService.getCommunityByServiceType(ServiceTypeConstant.CLEANING, communityNo);
            cleaningCommunityBo.setWorkmanCommunity(workmanCount);
            map.put(community.getDictLabel(), cleaningCommunityBo);
        }
        return map;
    }

    @Override
    public List<CleaningCommunityBo> getCleaningByCommunity() {
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(CommunityConstant.COMMUNITY_TYPE);
        List<SysDictData> communities = sysDictDataService.selectDictDataList(sysDictData);
        ArrayList<CleaningCommunityBo> cleaningCommunityBos = new ArrayList<>();
        communities.forEach(e-> {
            CleaningCommunityBo cleaningCommunityBo = new CleaningCommunityBo();
            CleaningCommunityMapBo communityByDate = this.getCommunityByDate(e.getDictLabel());
            BeanCopyUtils.copy(communityByDate,cleaningCommunityBo);
            cleaningCommunityBo.setCommunity(e.getDictLabel());
            cleaningCommunityBos.add(cleaningCommunityBo);
        });
        return cleaningCommunityBos;
    }

    @Override
    public List<CleaningCommunityCountBo> getCleaningCountByCommunity(String date) {
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(CommunityConstant.COMMUNITY_TYPE);
        List<SysDictData> communities = sysDictDataService.selectDictDataList(sysDictData);
        ArrayList<CleaningCommunityCountBo> cleaningCommunityCountBos = new ArrayList<>();
        communities.forEach(e-> {
            CleaningCommunityCountBo cleaningCommunityCountBo = new CleaningCommunityCountBo();
            cleaningCommunityCountBo.setCommunity(e.getDictLabel());
            String regionId = regionService.getRegionIdByName(e.getDictLabel());
            Double cleaningAreaSum = sweepCleaningMapper.selectCleaningCountByCommunity(date, regionId);
            if (null != cleaningAreaSum){
                cleaningCommunityCountBo.setAreaSum(BigDecimal.valueOf(cleaningAreaSum).setScale(2,RoundingMode.HALF_UP));
            } else {
                cleaningCommunityCountBo.setAreaSum(BigDecimal.ZERO);
            }
            ToolStatisticsBo toolCount = toolService.getCommunityByServiceTypeAndDate(ServiceTypeConstant.CLEANING, regionId,date);
            cleaningCommunityCountBo.setEquipmentCount(toolCount.getToolCount());
            cleaningCommunityCountBo.setVehicleCount(toolCount.getVehicleCount());
            int workmanCount = workmanService.getCommunityByServiceTypeAndDate(ServiceTypeConstant.CLEANING, regionId,date);
            cleaningCommunityCountBo.setWorkerCount(workmanCount);
            cleaningCommunityCountBos.add(cleaningCommunityCountBo);
        });
       return cleaningCommunityCountBos;
    }

    @Override
    public CleaningWorkStatisticsBo getCleaningWorkByDate(String date) {
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(CommunityConstant.COMMUNITY_TYPE);
        List<SysDictData> communities = sysDictDataService.selectDictDataList(sysDictData);
        ArrayList<Double> cleaningAreaSum = new ArrayList<>();
        communities.forEach(e-> {
            String regionId = regionService.getRegionIdByName(e.getDictLabel());
            Double areaSum = sweepCleaningMapper.selectCleaningCountByCommunity(date, regionId);
            if (null != areaSum ){
                cleaningAreaSum.add(areaSum);
            } else {
                cleaningAreaSum.add(0.00);
            }
        });
        CleaningWorkStatisticsBo cleaningWorkStatisticsBo = new CleaningWorkStatisticsBo();
        BigDecimal totalAreaSum = BigDecimal.valueOf(cleaningAreaSum.stream().reduce(Double::sum).orElse(0.00));
        cleaningWorkStatisticsBo.setTotalArea(totalAreaSum.toString());
        Double sumByDate = cleaningService.getSumByDate(date);
        BigDecimal finishedAreaSum = BigDecimal.ZERO;
        if (null != sumByDate) {
            finishedAreaSum = BigDecimal.valueOf(sumByDate).setScale(2,RoundingMode.HALF_UP);
        }
        cleaningWorkStatisticsBo.setFinishedAreaSum(finishedAreaSum.toString());
        if (finishedAreaSum.compareTo(BigDecimal.ZERO) <= 0 || totalAreaSum.compareTo(BigDecimal.ZERO) <= 0){
            cleaningWorkStatisticsBo.setPercent(BigDecimal.ZERO);
        } else {
            BigDecimal pec = finishedAreaSum.divide(totalAreaSum, 2, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100));
            pec = pec.compareTo(BigDecimal.valueOf(100)) > 0 ? BigDecimal.valueOf(100) : pec;
            cleaningWorkStatisticsBo.setPercent(pec);
        }
        return cleaningWorkStatisticsBo;
    }

    @Override
    public CleaningWorkStatisticsBo getCleaningWorkByDateAndCommunity(String date, String community) {
        CleaningWorkStatisticsBo cleaningWorkStatisticsBo = new CleaningWorkStatisticsBo();
        String regionId = regionService.getRegionIdByName(community);
        Double areaSum = sweepCleaningMapper.selectCleaningCountByCommunity(date, regionId);
        if (null != areaSum ){
            cleaningWorkStatisticsBo.setTotalArea(areaSum.toString());
        } else {
            cleaningWorkStatisticsBo.setTotalArea("0.00");
        }
        BigDecimal totalAreaSum = new BigDecimal(cleaningWorkStatisticsBo.getTotalArea());
        Double sumByDate = cleaningService.getSumByDateAndCommunity(date,community);
        BigDecimal finishedAreaSum = BigDecimal.ZERO;
        if (null != sumByDate) {
            finishedAreaSum = BigDecimal.valueOf(sumByDate).setScale(2,RoundingMode.HALF_UP);
        }
        cleaningWorkStatisticsBo.setFinishedAreaSum(finishedAreaSum.toString());
        if (finishedAreaSum.compareTo(BigDecimal.ZERO) <= 0 || totalAreaSum.compareTo(BigDecimal.ZERO) <= 0){
            cleaningWorkStatisticsBo.setPercent(BigDecimal.ZERO);
        } else {
            BigDecimal pec = finishedAreaSum.divide(totalAreaSum, 2, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100));
            pec = pec.compareTo(BigDecimal.valueOf(100)) > 0 ? BigDecimal.valueOf(100) : pec;
            cleaningWorkStatisticsBo.setPercent(pec);
        }
        return cleaningWorkStatisticsBo;
    }

    @Override
    public CleaningCommunityMapBo getCommunityByDate(String community) {
        CleaningCommunityMapBo cleaningCommunityMapBo = new CleaningCommunityMapBo();
        HashMap<String, String> map = new HashMap<>(32);
        String communityNo = regionService.getRegionIdByName(community);
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(SweepCleaningDirtConstant.CLEANING_TYPE);
        List<SysDictData> data = sysDictDataService.selectDictDataList(sysDictData);
        List<CleaningRoadTypeBo> cleaningRoadTypeBos = sweepCleaningMapper.selectCommunityAreaCount(communityNo);
        buildCleaningTypeMap(data,cleaningRoadTypeBos,map);
        cleaningCommunityMapBo.setCleaningTypeMap(map);
        ToolStatisticsBo toolCount = toolService.getCountByServiceTypeAndCommunity(ServiceTypeConstant.CLEANING, communityNo);
        if (null != toolCount){
            cleaningCommunityMapBo.setToolCount(toolCount.getToolCount());
            cleaningCommunityMapBo.setVehicleCount(toolCount.getVehicleCount());
        } else {
            cleaningCommunityMapBo.setToolCount(0);
            cleaningCommunityMapBo.setVehicleCount(0);
        }
        int workmanCount = workmanService.getCommunityByServiceType(ServiceTypeConstant.CLEANING, communityNo);
        cleaningCommunityMapBo.setWorkmanCommunity(workmanCount);
        return cleaningCommunityMapBo;
    }

    @Override
    public Double getCleaningByDateAndCommunity(String date, String community) {
        Double cleaningCount;
        if (StringUtils.isNotEmpty(community)) {
            String regionIdByName = regionService.getRegionIdByName(community);
            cleaningCount = sweepCleaningMapper.selectCleaningCountByCommunity(date, regionIdByName);
        } else {
            cleaningCount = sweepCleaningMapper.selectCleaningCountByCommunity(date, null);
        }
        if (null == cleaningCount) {
            cleaningCount = 0d;
        }
        return cleaningCount;
    }

    /**
     * 组装数据
     * @param data
     * @param cleaningRoadTypeBos
     * @param map
     */
    private void buildCleaningTypeMap(List<SysDictData> data,List<CleaningRoadTypeBo> cleaningRoadTypeBos,HashMap<String, String> map){
        ArrayList<String> typeName = new ArrayList<>();
        for (SysDictData cleaningType : data) {
            if (cleaningRoadTypeBos.size() > 0) {
                for (CleaningRoadTypeBo roadTypeBo : cleaningRoadTypeBos) {
                    if (cleaningType.getDictValue().equals(roadTypeBo.getRoadType())) {
                        typeName.add(cleaningType.getDictLabel());
                        map.put(cleaningType.getDictLabel(),roadTypeBo.getAreaSum());
                    }
                }
            } else {
                map.put(cleaningType.getDictLabel(),"0");
            }
        }
        if (typeName.size() > 0) {
            List<String> labelList = data.stream().map(SysDictData::getDictLabel).collect(Collectors.toList());
            labelList.removeAll(typeName);
            labelList.forEach(e->{
                map.put(e,"0");
            });
        }
    }

}
